package com.ihg.hiex.admin.service.session.impl;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.utils.CollectionUtils;
import com.ihg.hiex.admin.dao.session.CareerWorkDao;
import com.ihg.hiex.admin.dao.session.ReportWritingDao;
import com.ihg.hiex.admin.dao.session.SessionCalibrationDao;
import com.ihg.hiex.admin.dao.session.SessionDao;
import com.ihg.hiex.admin.dao.session.SessionReportDao;
import com.ihg.hiex.admin.dao.session.SessionReportWritingDao;
import com.ihg.hiex.admin.entity.dto.BeBrandHearted;
import com.ihg.hiex.admin.entity.dto.Competency;
import com.ihg.hiex.admin.entity.dto.Overall;
import com.ihg.hiex.admin.entity.dto.OverallEvaluation;
import com.ihg.hiex.admin.entity.dto.Swift;
import com.ihg.hiex.admin.handler.PDFHandler;
import com.ihg.hiex.admin.handler.ParseHandler;
import com.ihg.hiex.admin.handler.ZipHandler;
import com.ihg.hiex.admin.service.session.ReportWritingService;
import com.ihg.hiex.entity.session.Session;
import com.ihg.hiex.entity.session.SessionAttribute;
import com.ihg.hiex.entity.session.after.ReportGenerateStatus;
import com.ihg.hiex.entity.session.after.SessionReport;
import com.ihg.hiex.entity.session.before.delegatework.DelegateCareerGoals;
import com.ihg.hiex.entity.session.before.delegatework.DelegateWrokRecord;
import com.ihg.hiex.entity.session.during.SessionCalibration;
import com.ihg.hiex.entity.session.during.report.SessionReportComment;
import com.ihg.hiex.entity.session.during.report.SessionReportRecommendation;
import com.ihg.hiex.entity.session.during.report.SessionReportWriting;
import com.ihg.hiex.entity.session.during.report.SingleScore;
import com.ihg.hiex.entity.session.during.report.SingleSummaryScore;
import com.ihg.hiex.entity.session.during.report.SumScore;
import com.ihg.hiex.entity.user.Delegate;

/**
 * 
 * @author dan
 *
 */
@Service("reportWritingService")
public class ReportWritingServiceImpl implements ReportWritingService{
    
    @Dao
    private ReportWritingDao reportWritingDao;
    
    @Dao
    private SessionCalibrationDao sessionCalibrationDao;
    
    @Dao
    private SessionReportDao sessionReportDao;
    
    @Dao
    private SessionReportWritingDao sessionReportWritingDao;
    
    @Dao
    private CareerWorkDao careerWorkDao;
    
    @Dao
    private SessionDao sessionDao;
    
    @Autowired
    private ParseHandler parseHandler;
    
    @Autowired
    private PDFHandler pdfHandler;
    
    @Autowired
    private ZipHandler zipHandler;
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;
    
    private final static Logger logger = LoggerFactory.getLogger(ReportWritingServiceImpl.class);
    
    private final static String[] externalBenchmark = new String[]{"2%", "7%", "16%", "31%", "50%", "69%", "84%", "93%", "98%", "100%"};

    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.ReportWritingService#getCompetencyScore(com.ihg.hiex.entity.session.during.SessionCalibration, com.ihg.hiex.admin.entity.dto.Competency)
     */
    @SuppressWarnings("unchecked")
    public Competency getCompetencyScore(SessionCalibration calibration, Competency competency) {
        
        Long calibrationId = calibration.getId();
        
        // get brandHearted
        List<SingleScore> brandHearteds = reportWritingDao.listSingleScoreByName("Be BrandHearted");
        Map<String, SingleScore> bbScores = CollectionUtils.constructMapValue(brandHearteds, "sessionCalibrationId");
        List<Long> brandHeartedIds = CollectionUtils.extractPropertyList(brandHearteds, "sessionCalibrationId");
        List<SingleSummaryScore> bbSumary = reportWritingDao.listSingleSummaryScore("Be BrandHearted");
        String brandHeartedIB = this.getInternalBenchmark(bbScores.get(calibrationId.toString()), bbSumary);
        String brandHeartedAE = this.getAssessorEvaluation(brandHearteds, brandHeartedIds, calibrationId);
        BeBrandHearted beBrandHearted = new BeBrandHearted(brandHeartedAE, brandHeartedIB);
        competency.editBeBrandHearted(beBrandHearted);
        
        // get driveResult internalBenchmark
        List<SingleScore> driveResults = reportWritingDao.listSingleScoreByName("Drive Result");
        Map<String, SingleScore> drScores = CollectionUtils.constructMapValue(driveResults, "sessionCalibrationId");
        List<Long> driveResultIds = CollectionUtils.extractPropertyList(driveResults, "sessionCalibrationId");
        List<SingleSummaryScore> drSumary = reportWritingDao.listSingleSummaryScore("Drive Result");
        String driveResultIB = this.getInternalBenchmark(drScores.get(calibrationId.toString()), drSumary);
        String driveResultEB = externalBenchmark[competency.getDriveResult().getPotential()-1];
        String driveResultAE = this.getAssessorEvaluation(driveResults, driveResultIds, calibrationId);
        competency.getDriveResult().init(driveResultAE, driveResultIB, driveResultEB);
        
        // get ChampionChange internalBenchmark
        List<SingleScore> championChanges = reportWritingDao.listSingleScoreByName("Champion Change");
        Map<String, SingleScore> ccScores = CollectionUtils.constructMapValue(championChanges, "sessionCalibrationId");
        List<Long> championChangeIds = CollectionUtils.extractPropertyList(championChanges, "sessionCalibrationId");
        List<SingleSummaryScore> ccSumary = reportWritingDao.listSingleSummaryScore("Champion Change");
        String championChangeIB = this.getInternalBenchmark(ccScores.get(calibrationId.toString()), ccSumary);
        String championChangeEB = externalBenchmark[competency.getChampionChange().getPotential()-1];
        String championChangeAE = this.getAssessorEvaluation(championChanges, championChangeIds, calibrationId);
        competency.getChampionChange().init(championChangeAE, championChangeIB, championChangeEB);
        
        // get leadAndDevelopment internalBenchmark
        List<SingleScore> leadAndDevelopments = reportWritingDao.listSingleScoreByName("Lead And Development");
        Map<String, SingleScore> ldScores = CollectionUtils.constructMapValue(leadAndDevelopments, "sessionCalibrationId");
        List<Long> leadAndDevelopmentIds = CollectionUtils.extractPropertyList(leadAndDevelopments, "sessionCalibrationId");
        List<SingleSummaryScore> ldSumary = reportWritingDao.listSingleSummaryScore("Lead And Development");
        String leadAndDevelopmentIB = this.getInternalBenchmark(ldScores.get(calibrationId.toString()), ldSumary);
        String leadAndDevelopmentEB = externalBenchmark[competency.getLeadAndDevelop().getPotential()-1];
        String leadAndDevelopmentAE = this.getAssessorEvaluation(leadAndDevelopments, leadAndDevelopmentIds, calibrationId);
        competency.getLeadAndDevelop().init(leadAndDevelopmentAE, leadAndDevelopmentIB, leadAndDevelopmentEB);
        
        // get Be BrandHearted internalBenchmark
        List<SingleScore> workCollaborativelys = reportWritingDao.listSingleScoreByName("Work Collaboratively");
        Map<String, SingleScore> wcScores = CollectionUtils.constructMapValue(workCollaborativelys, "sessionCalibrationId");
        List<Long> workCollaborativelyIds = CollectionUtils.extractPropertyList(workCollaborativelys, "sessionCalibrationId");
        List<SingleSummaryScore> wcSumary = reportWritingDao.listSingleSummaryScore("Work Collaboratively");
        String workCollaborativelyIB = this.getInternalBenchmark(wcScores.get(calibrationId.toString()), wcSumary);
        String workCollaborativelyEB = externalBenchmark[competency.getWorkCollaboratively().getPotential()-1];
        String workCollaborativelyAE = this.getAssessorEvaluation(workCollaborativelys, workCollaborativelyIds, calibrationId);
        competency.getWorkCollaboratively().init(workCollaborativelyAE, workCollaborativelyIB, workCollaborativelyEB);
        
        // get Financial Management internalBenchmark
        List<SingleScore> financialManagements = reportWritingDao.listSingleScoreByName("Financial Management");
        Map<String, SingleScore> fmScores = CollectionUtils.constructMapValue(financialManagements, "sessionCalibrationId");
        List<Long> financialManagementIds = CollectionUtils.extractPropertyList(financialManagements, "sessionCalibrationId");
        List<SingleSummaryScore> fmSumary = reportWritingDao.listSingleSummaryScore("Financial Management");
        String financialManagementIB = this.getInternalBenchmark(fmScores.get(calibrationId.toString()), fmSumary);
        String financialManagementEB = externalBenchmark[competency.getFinancialManagement().getPotential()-1];
        String financialManagementAE = this.getAssessorEvaluation(financialManagements, financialManagementIds, calibrationId);
        competency.getFinancialManagement().init(financialManagementAE, financialManagementIB, financialManagementEB);
        
        return competency;
    }
    
    /**
     * 
     * @param singleScore
     * @param summaries
     * @return
     */
    private String getInternalBenchmark(SingleScore singleScore, List<SingleSummaryScore> summaries) {
        long index = 0;
        long sum = 0;
        for(int i = 0; i<summaries.size(); i++) {
            if(singleScore.getSingleScore() == summaries.get(i).getScore()) {
                for(int j = 0; j<=i; j++) {
                    index = index + summaries.get(j).getScoreSum();
                }
            }
            sum = sum + summaries.get(i).getScoreSum();
        }
        BigDecimal benchmark = new BigDecimal(index).divide(new BigDecimal(sum), 2,BigDecimal.ROUND_HALF_UP);
        return benchmark.multiply(new BigDecimal(100)).intValue() + "%";
    }
    
    /**
     * 
     * @param singleScores
     * @param calibrationIds
     * @param calibrationId
     * @return
     */
    private String getAssessorEvaluation(List<SingleScore> singleScores, List<Long> calibrationIds, Long calibrationId) {
        int index = calibrationIds.indexOf(calibrationId);
        int singleScore = singleScores.get(index).getSingleScore();
        return singleScore == 1 ? "DN" : singleScore == 3 ? "C" :"S";
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.ReportWritingService#getOverall(com.ihg.hiex.entity.session.during.SessionCalibration)
     */
    @SuppressWarnings("unchecked")
    public Overall getOverall(SessionCalibration calibration) {
        List<OverallEvaluation> evaluations = reportWritingDao.listOverallEvaluation(calibration.getId());
        
        String name = "";
        for(OverallEvaluation evaluation : evaluations) {
            name = name + evaluation.getName() + "-";
        }
        
        String assessorEvalution = name.substring(0, name.length() - 1);
        
        List<SumScore> sumScores = reportWritingDao.listSumScore();
        List<Long> calibrationIds = CollectionUtils.extractPropertyList(sumScores, "sessionCalibrationId");
        int index = calibrationIds.indexOf(calibration.getId());
        
        BigDecimal benchmark = new BigDecimal(index+1).divide(new BigDecimal(sumScores.size()), 2,BigDecimal.ROUND_HALF_UP);
        String internalBenchmark = benchmark.multiply(new BigDecimal(100)).intValue() + "%";
        
        return new Overall(assessorEvalution, internalBenchmark);
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.ReportWritingService#batchGeneratePplReport()
     */
    public void batchGeneratePplReport() {
        List<SessionReport> sessionReports = sessionReportDao.listPplReport(ReportGenerateStatus.GENERATING);
        
        for(SessionReport sessionReport : sessionReports) {
            
            Session session = sessionReport.getSession();
            Delegate delegate = sessionReport.getDelegate();
            SessionCalibration sessionCalibration = sessionCalibrationDao.loadCalibration(session, delegate);
            List<SessionAttribute> atttributes = sessionDao.listSessionAttribute(session, new String[]{"wave-data", "swift-data"});
            Map<String, SessionAttribute> sessionAtttributes = CollectionUtils.constructMapValue(atttributes, "name");
            
            // parse waveFile and get competency
            Competency competency = parseHandler.parseWave(delegate.getEmail(), sessionAtttributes.get("wave-data").getValue());
            competency = this.getCompetencyScore(sessionCalibration, competency);
            
            // parse swiftFile and get swift
            Swift swift = parseHandler.parseSwift(delegate.getEmail(), sessionAtttributes.get("swift-data").getValue());
            
            // get overall
            Overall overall = this.getOverall(sessionCalibration);
            
            // get sessionCalibrationRecommendation
            SessionReportWriting reportWriting = sessionReportWritingDao.load(sessionCalibration);
            SessionReportRecommendation recommendation = reportWriting.getSessionReportRecommendation();
            
            String peoplePlanReport = pdfHandler.savePeoplePlaningReport(sessionCalibration.getSession(), delegate, swift, competency, overall, recommendation);
            
            genericDaoSupport.update(sessionReport.editReport(peoplePlanReport, "assessorFinalReport"));
        }
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.ReportWritingService#batchGenerateManagerReport()
     */
    public void batchGenerateManagerReport() {
        List<SessionReport> sessionReports = sessionReportDao.listManagerReport(ReportGenerateStatus.GENERATING);
        
        for(SessionReport sessionReport : sessionReports) {
            
            Session session = sessionReport.getSession();
            Delegate delegate = sessionReport.getDelegate();
            SessionCalibration sessionCalibration = sessionCalibrationDao.loadCalibration(session, delegate);
            List<SessionAttribute> atttributes = sessionDao.listSessionAttribute(session, new String[]{"wave-data", "swift-data"});
            Map<String, SessionAttribute> sessionAtttributes = CollectionUtils.constructMapValue(atttributes, "name");
            
            Competency competency = parseHandler.parseWave(delegate.getEmail(), sessionAtttributes.get("wave-data").getValue());
            competency = this.getCompetencyScore(sessionCalibration, competency);
            
            List<DelegateWrokRecord> wrokRecords = careerWorkDao.listWorkRecord(delegate);
            DelegateCareerGoals goals = careerWorkDao.loadCareerGoals(delegate);
            
            SessionReportWriting reportWriting = sessionReportWritingDao.load(sessionCalibration);
            SessionReportComment comment = reportWriting.getSessionReportComment();
            
            String delegateReport  = pdfHandler.savaDelegateReport(sessionCalibration.getSession(), sessionCalibration.getLeadAssessor(), delegate, wrokRecords, goals, competency, comment, false);
            
            genericDaoSupport.update(sessionReport.editReport(delegateReport, "coachFinalReport"));
        }
    }
    
    /*
     * (non-Javadoc)
     * @see com.ihg.hiex.admin.service.session.ReportWritingService#batchGenerateDelegateReport()
     */
    public void batchGenerateDelegateReport() {
        
        List<SessionReport> sessionReports = sessionReportDao.listDelegateReport(ReportGenerateStatus.GENERATING);
        
        for(SessionReport sessionReport : sessionReports) {
            String path = sessionReport.getSession().getName() + "/" + sessionReport.getDelegate().getName() + "/report";
            try {
                String zipUrl = zipHandler.zipFile(path, "delegate-final-report", sessionReport);
                genericDaoSupport.update(sessionReport.editReport(zipUrl, "delegateFinalReport"));
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }
        
    }

}
